﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace ESpace
{

    public class EStream
    {
        String FName;
        FileStream Sv;
        BinaryWriter w = null;
        BinaryReader r = null;

        //конструктор
        public EStream(String FN)
        {
            FName = FN;
        }
        //---------------------------------------------------------------------------
        #region OpenClose

        public void OpenLoad()
        {
            Sv = new FileStream(FName, FileMode.Open, FileAccess.Read);
            r = new BinaryReader(Sv);
        }
        public void OpenSave()
        {
            Sv = new FileStream(FName, FileMode.Create);
            w = new BinaryWriter(Sv);
        }

        public void Close()
        {
            if (r != null) r.Close();
            else w.Close();
            Sv.Close();
        }

        #endregion OpenClose
        //---------------------------------------------------------------------------
        public String LoadStr()
        {
            String str = "";
            try
            {
                int sz = r.ReadInt32();
                for (int i = 0; i < sz; i++)
                    str += r.ReadChar();
            }
            catch { };
            return str;
        }
        public void SaveStr(String s)
        {
            int sz = 0;
            if (s != null) sz = s.Length;
            w.Write(sz);
            for (int i = 0; i < sz; i++)
            {
                w.Write((char)s[i]);
            }
        }
        //---------------------------------------------------------------------------
        public byte[] LoadBuf()
        {
            int sz = LoadInt();
            return r.ReadBytes(sz);
        }
        public void SaveBuf(byte[] buf)
        {
            SaveInt(buf.Length);
            w.Write(buf);
        }
        //---------------------------------------------------------------------------
        public Bitmap LoadBmp()
        {
            int w = LoadInt();
            int h = LoadInt();
            System.Drawing.Imaging.PixelFormat pf = (System.Drawing.Imaging.PixelFormat)LoadInt();
            byte[] buf = LoadBuf();

            Bitmap bmp = new Bitmap(w, h);

            // блокируем bmp
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, pf);

            // находим адрес на первую линию bmp
            IntPtr ptr = bmpData.Scan0;

            // копируем массив в bmp
            System.Runtime.InteropServices.Marshal.Copy(buf, 0, ptr, bmpData.Stride * bmp.Height);

            // разблокируем bmp.
            bmp.UnlockBits(bmpData);

            return bmp;
        }
        public void SaveBmp(Bitmap bmp)
        {
            // сохраняем размеры bmp
            SaveInt(bmp.Width);
            SaveInt(bmp.Height);
            SaveInt((int)bmp.PixelFormat);

            // блокируем bmp
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);

            // находим адрес на первую линию bmp
            IntPtr ptr = bmpData.Scan0;

            // создаем массив байт
            int sz = bmpData.Stride * bmp.Height;
            byte[] rgbValues = new byte[sz];

            // копируем значения RGB в массив
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, sz);

            // сохраняем массив
            SaveBuf(rgbValues);

            // разблокируем bmp.
            bmp.UnlockBits(bmpData);
        }
        //---------------------------------------------------------------------------
        public DateTime LoadDate()
        {
            return new DateTime(r.ReadInt64());
        }
        public void SaveDate(DateTime dt)
        {
            w.Write(dt.Ticks);
        }
        //---------------------------------------------------------------------------
        public int LoadInt()
        {
            return r.ReadInt32();
        }
        public void SaveInt(int i)
        {
            w.Write(i);
        }
        //---------------------------------------------------------------------------
        public double LoadDouble()
        {
            return r.ReadDouble();
        }
        public void SaveDouble(double d)
        {
            w.Write(d);
        }
        //---------------------------------------------------------------------------
        public byte LoadByte()
        {
            return r.ReadByte();
        }
        public void SaveByte(byte b)
        {
            w.Write(b);
        }
        //---------------------------------------------------------------------------
        public bool LoadBool()
        {
            return r.ReadBoolean();
        }
        public void SaveBool(bool b)
        {
            w.Write(b);
        }
        //---------------------------------------------------------------------------
        public long LoadLong()
        {
            return r.ReadInt64();
        }
        public void SaveLong(long b)
        {
            w.Write(b);
        }
        //---------------------------------------------------------------------------

    }

    public class BinReader
    {
        int n = 0;
        byte[] buf;
        public BinReader(byte[] buf)
        {
            this.buf = buf;
        }

        public void New(byte[] buf)
        {
            this.buf = buf;
            n = 0;
        }

        public byte ReadByte()
        {
            if (n >= buf.Length) throw new Exception("Ошибка разбора пакета: Ошибка чтения байта");
            n++;
            return buf[n - 1];
        }

        public short ReadShort()
        {
            try
            {
                short ret = BitConverter.ToInt16(buf, n);
                n += 2;
                return ret;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения Short >> " + ex.Message); }
        }

        public int ReadInt()
        {
            try
            {
                int ret = BitConverter.ToInt32(buf, n);
                n += 4;
                return ret;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения Int >> " + ex.Message); }
        }

        public long ReadLong()
        {
            try
            {
                long ret = BitConverter.ToInt64(buf, n);
                n += 8;
                return ret;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения Long >> " + ex.Message); }
        }

        public float ReadFloat()
        {
            try
            {
                float ret = BitConverter.ToSingle(buf, n);
                n += 4;
                return ret;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения Float >> " + ex.Message); }
        }

        public double ReadDouble()
        {
            try
            {
                double ret = BitConverter.ToDouble(buf, n);
                n += 8;
                return ret;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения Double >> " + ex.Message); }
        }

        public DateTime ReadDateTime()
        {
            try
            {
                return new DateTime(ReadLong());
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения DateTime >> " + ex.Message); }
        }

        public String ReadString()
        {
            try
            {
                byte[] buf = ReadMas();
                String s = "";
                try
                {
                    s = Encoding.Unicode.GetString(buf);
                }
                catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения строки >> " + ex.Message); }
                return s;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения строки >> " + ex.Message); }

        }

        public String ReadStringASCII()
        {
            try
            {
                byte[] buf = ReadMas();
                String s = "";
                try
                {
                    s = Encoding.ASCII.GetString(buf);
                }
                catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения строки ASCII >> " + ex.Message); }
                return s;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения строки ASCII >> " + ex.Message); }

        }

        public byte[] ReadMas()
        {
            try
            {
                int len = ReadInt();
                if (len < 0) throw new Exception("Ошибка разбора пакета: Ошибка чтения массива байт >> Неверная длина буфера");
                if ((n + len) > buf.Length) throw new Exception("Ошибка разбора пакета: Ошибка чтения массива байт >> Неверная длина буфера");

                byte[] b = new byte[len];
                for (int i = 0; i < len; i++)
                {
                    b[i] = buf[n + i];
                }
                n += len;
                return b;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения массива байт >> " + ex.Message); }
        }

        public bool[] ReadBitMas()
        {
            try
            {
                int len = ReadInt();
                if (len < 0) throw new Exception("Ошибка разбора пакета: Ошибка чтения бит-массива >> Неверная длина буфера");

                if (len % 8 == 0)
                {
                    if ((n + len / 8) > buf.Length) return null;
                }
                else
                {
                    if ((n + len / 8 + 1) > buf.Length) return null;
                }

                bool[] b = new bool[len];
                int razr = 1; // разряд
                for (int i = 0; i < len; i++)
                {
                    b[i] = (buf[n + i / 8] & razr) != 0;
                    razr *= 2;
                    if (razr == 256) razr = 1;
                }

                if (len % 8 == 0) n += len / 8;
                else n += len / 8 + 1;

                return b;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения бит-массива >> " + ex.Message); }
        }

        public Bitmap ReadBmp()
        {
            try
            {
                int pW = ReadShort();
                int pH = ReadShort();
                Bitmap bmp = new Bitmap(pW, pH);

                // Блокирует битмап без копирования 
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
                // Get the address of the first line.
                IntPtr ptr = bmpData.Scan0;

                // читаем
                byte[] rgbValues = ReadMas();

                // копируем в битмап
                if (rgbValues != null)
                {
                    System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, rgbValues.Length);
                }
                // разблокируем битмап
                bmp.UnlockBits(bmpData);

                return bmp;
            }
            catch (Exception ex) { throw new Exception("Ошибка разбора пакета: Ошибка чтения Bmp >> " + ex.Message); }
        }
    }

    public class BinWriter
    {
        // оператор сложения
        public static BinWriter operator +(BinWriter b1, BinWriter b2)
        {
            if (b1 == null & b2 == null) return null;
            BinWriter bw = new BinWriter();
            if (b1 != null)
                for (int i = 0; i < b1.bl.Count; i++)
                    bw.bl.Add(b1.bl[i]);
            if (b2 != null)
                for (int i = 0; i < b2.bl.Count; i++)
                    bw.bl.Add(b2.bl[i]);
            return bw;
        }

        protected List<byte> bl = new List<byte>();

        public byte[] buf { get { return bl.ToArray(); } }

        /// <summary> добавить массив </summary>
        public void AddBufWriterMas(byte[] YBinWriterBuf)
        {
            for (int i = 0; i < YBinWriterBuf.Length; i++)
                bl.Add(YBinWriterBuf[i]);
        }

        public BinWriter()
        {
        }

        public void New()
        {
            bl.Clear();
        }

        public void WriteByte(byte b) { bl.Add(b); }

        public void WriteShort(short n)
        {
            AddBufWriterMas(BitConverter.GetBytes(n));
        }

        public void WriteInt(int n)
        {
            AddBufWriterMas(BitConverter.GetBytes(n));
        }

        public void WriteLong(long n)
        {
            AddBufWriterMas(BitConverter.GetBytes(n));
        }

        public void WriteFloat(float f)
        {
            AddBufWriterMas(BitConverter.GetBytes(f));
        }

        public void WriteDouble(double d)
        {
            AddBufWriterMas(BitConverter.GetBytes(d));
        }

        public void WriteDateTime(DateTime dt)
        {
            WriteLong(dt.Ticks);
        }

        public void WriteString(String s)
        {
            WriteMas(Encoding.Unicode.GetBytes(s));
        }

        public void WriteStringASCII(String s)
        {
            WriteMas(Encoding.ASCII.GetBytes(s));
        }

        public void WriteMas(byte[] b)
        {
            WriteInt(b.Length);
            for (int i = 0; i < b.Length; i++)
                bl.Add(b[i]);
        }

        public void WriteBitMas(bool[] b)
        {
            WriteInt(b.Length);
            int n = 1;
            int actB = 0;
            for (int i = 0; i < b.Length; i++)
            {
                if (b[i]) actB = actB | n;
                n *= 2;
                if (n == 256)
                {
                    n = 1;
                    bl.Add((byte)actB);
                    actB = 0;
                }
            }
            // если есть еще записанные биты
            if (n > 1) bl.Add((byte)actB);
        }

        public void WriteBmp(Bitmap bmp)
        {
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
            // Get the address of the first line.
            IntPtr ptr = bmpData.Scan0;
            // Declare an array to hold the bytes of the bitmap.
            int bytes = bmpData.Stride * bmp.Height;
            byte[] rgbValues = new byte[bytes];
            // Копируем битмап в массив байт.
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

            // пишем
            WriteShort((short)bmp.Width);
            WriteShort((short)bmp.Height);
            WriteMas(rgbValues);

            // разблокируем битмап
            bmp.UnlockBits(bmpData);
        }

    }
}
  
